package net.ufrog.common.weixin;

import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import net.ufrog.common.Logger;
import net.ufrog.common.exception.ServiceException;
import net.ufrog.common.utils.Cryptos;
import net.ufrog.common.utils.Cryptos.HashType;
import net.ufrog.common.utils.Strings;
import net.ufrog.common.weixin.pojos.AccessToken;
import net.ufrog.common.weixin.pojos.Err;
import net.ufrog.common.weixin.xpp.CdataXppDriver;

import com.alibaba.fastjson.JSON;
import com.thoughtworks.xstream.XStream;

/**
 * 微信接口
 * 
 * @author ultrafrog
 * @version 1.0, 2014-12-29
 * @since 1.0
 */
public abstract class Apis {

	public static final String HOST		= "https://api.weixin.qq.com";
	public static final String CGI_URL	= HOST + "/cgi-bin";
	public static final String SNS_URL	= HOST + "/sns";
	public static final String PAY_URL	= "https://api.mch.weixin.qq.com";
	
	private static XStream xstream = new XStream(new CdataXppDriver());
	
	/**
	 * 验证签名<br>
	 * 服务地址验证
	 * 
	 * @param token
	 * @param timestamp
	 * @param nonce
	 * @param signature
	 * @return
	 */
	public static Boolean checkSignature(String token, String timestamp, String nonce, String signature) {
		List<String> strs = Arrays.asList(token, timestamp, nonce);
		Collections.sort(strs);
		String implode = Strings.implode(strs, "");
		String sha1 = Cryptos.hashAndHex(implode, HashType.SHA1);
		
		Logger.info("hash str: %s, sha1: %s, original: %s", implode, sha1, signature);
		return Strings.equals(signature, sha1);
	}
	
	/**
	 * 获取访问令牌
	 * 
	 * @param appId
	 * @param appSecret
	 * @return
	 */
	public static AccessToken getAccessToken(String appId, String appSecret) {
		String url = url(CGI_URL, "/token?grant_type=client_credential&appid=%s&secret=%s", appId, appSecret);
		HttpResponse resp = HttpRequest.get(url).send();
		AccessToken accessToken = fromJson(resp, AccessToken.class);
		return checkErr(accessToken);
	}
	
	/**
	 * 解析响应
	 * 
	 * @param resp
	 * @param type
	 * @return
	 */
	public static <T extends Serializable> T fromJson(HttpResponse resp, Class<T> type) {
		try {
			String json = new String(resp.bodyBytes(), "utf-8");
			Logger.debug("weixin response json: %s", json);
			return JSON.parseObject(json, type);
		} catch (UnsupportedEncodingException e) {
			throw new ServiceException(e.getMessage(), e);
		}
	}
	
	/**
	 * 检查消息结果
	 * 
	 * @param err
	 * @return
	 */
	public static <T extends Err> T checkErr(T err) {
		if (!err.success()) {
			throw new ServiceException(err.toString() + "@" + err.getMessage());
		}
		return err;
	}
	
	/**
	 * 解析消息
	 * 
	 * @param inputStream
	 * @return
	 */
	public static <T> T fromXML(InputStream inputStream, Class<T> clazz) {
		try {
			T message = clazz.newInstance();
			xstream.processAnnotations(clazz);
			xstream.fromXML(inputStream, message);
			return message;
		} catch (InstantiationException | IllegalAccessException e) {
			throw new ServiceException(e.getMessage(), e);
		}
	}
	
	/**
	 * 序列化消息
	 * 
	 * @param message
	 * @return
	 */
	public static String toXML(Object message) {
		xstream.processAnnotations(message.getClass());
		return xstream.toXML(message).replaceAll("__", "_");
	}
	
	/**
	 * 生成请求地址
	 * 
	 * @param host
	 * @param uri
	 * @param args
	 * @return
	 */
	public static String url(String host, String uri, Object... args) {
		return String.format(host + uri, args);
	}

	/**
	 * @param args
	 */
	public static void main(String... args) {
		AccessToken accessToken = getAccessToken("wx368f94eceb622f3f", "8f205246dcfc21d0ef3922c823b8e4c5");
		System.out.println(accessToken.getAccessToken());
	}
}
